package xyz.xpman.prisonerfitness.entity;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;

import androidx.annotation.RequiresApi;

import org.jetbrains.annotations.NotNull;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import xyz.xpman.prisonerfitness.R;
import xyz.xpman.prisonerfitness.util.BitmapUtil;
import xyz.xpman.prisonerfitness.util.JsonUtil;
import xyz.xpman.prisonerfitness.util.StreamUtils;

@SuppressWarnings("unused")
@RequiresApi(api = Build.VERSION_CODES.N)
public class Mappings implements Serializable {
    public static final String GUIDE_KEY = "guide";

    private static List<Moves> moves = Collections.emptyList();
    private static List<Chapter> chapters = Collections.emptyList();

    private static final Map<String, Moves> ID_MOVES = new HashMap<>();
    private static final Map<String, Chapter> ID_CHAPTERS = new HashMap<>();
    private static final Map<String, Set<Moves>> chapter_moves = new HashMap<>();

    @SuppressLint("StaticFieldLeak")
    private static Context context = null;

    private Mappings() {}



    public static void init(@NotNull Context context) {
        if (null != Mappings.context) {
            return;
        }

        Mappings.context = context;

        initChapters();
        initMoves();
        initMapping();

        moves = Collections.unmodifiableList(new ArrayList<>(ID_MOVES.values()));
        chapters = Collections.unmodifiableList(new ArrayList<>(ID_CHAPTERS.values()));
    }


    private static void initChapters() {
        final Map<String, Chapter> items = new HashMap<>();
        String json = StreamUtils.get(context, R.raw.chapters);

        try {
            JSONArray jsonArray = new JSONArray(json);

            for(int i = 0; i < jsonArray.length(); i++){
                Chapter chapter = Chapter.byJson(jsonArray.getJSONObject(i));

                items.put(chapter.getId(), chapter);
            }
            ID_CHAPTERS.putAll(items);
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    private static void initMoves() {
        final Map<String, Moves> items = new HashMap<>();
        String json = StreamUtils.get(context, R.raw.moves);

        try {
            JSONArray jsonArray = new JSONArray(json);

            for(int i = 0; i < jsonArray.length(); i++){
                Moves moves = Moves.byJson(jsonArray.getJSONObject(i));

                items.put(moves.getId(), moves);
            }
            ID_MOVES.putAll(items);
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    private static void initMapping() {
        for (Map.Entry<String, LinkedHashSet<String>> entry
                : getMapping().entrySet()) {
            final String chapterId = entry.getKey();
            final Set<String> movesIds = entry.getValue();

            final Set<Moves> items = new LinkedHashSet<>(movesIds.size());

            for (String movesId : movesIds) {
                Moves moves = ID_MOVES.get(movesId);

                if (null != moves) {
                    moves.setChapterId(chapterId);
                    items.add(moves);
                }

                // Log.i("Mappings", "chapterId: " + movesId + ", movesIds: " + moves);
            }

            chapter_moves.put(chapterId, Collections.unmodifiableSet(items));
        }

    }

    /**
     * 获取mapping
     *
     * @return  Map<chapterId:String, moves:LinkedHashSet<movesId:String>>
     */
    private static Map<String, LinkedHashSet<String>> getMapping() {
        Map<String, LinkedHashSet<String>> items = new HashMap<>();
        String json = StreamUtils.get(context, R.raw.cm_mapping);

        try {
            JSONObject object = new JSONObject(json);
            JSONArray namesJsonArray = object.names();

            if (null == namesJsonArray) {
                return Collections.emptyMap();
            }


            final String[] names = JsonUtil.toStringArray(namesJsonArray);

            for (String name : names) {
                JSONArray jsonArray = object.getJSONArray(name);

                final LinkedHashSet<String> moves = new LinkedHashSet<>();

                for(int i = 0; i < jsonArray.length(); i++){
                    moves.add(jsonArray.getString(i));
                }

                items.put(name, moves);
            }
        } catch (Exception e){
            e.printStackTrace();
        }
        return items;
    }



    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



    public static List<Moves> getMoves() {
        return moves;
    }

    public static List<Chapter> getChapters() {
        return chapters;
    }


    public static Moves getMove(String id) {
        return ID_MOVES.get(id);
    }

    public static Chapter getChapter(String id) {
        return ID_CHAPTERS.get(id);
    }



    public static Set<Moves> getMoves(String chapterId) {
        return chapter_moves.getOrDefault(chapterId, Collections.emptySet());
    }



    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



    @SuppressLint("UseCompatLoadingForDrawables")
    static class ChaptersFlagImgMapping{
        private static final Map<String, Bitmap> map = Map.ofEntries(
                Map.entry("101", getBitmap(R.drawable.moves_set1)),
                Map.entry("102", getBitmap(R.drawable.moves_set2)),
                Map.entry("103", getBitmap(R.drawable.moves_set3)),
                Map.entry("104", getBitmap(R.drawable.moves_set4)),
                Map.entry("105", getBitmap(R.drawable.moves_set5)),
                Map.entry("106", getBitmap(R.drawable.moves_set6)));

        @SuppressLint("ResourceType")
        private static Bitmap getBitmap(int id) {
            /*
                context.getDrawable(id) 和
                context.getResources().getDrawable(id)
                不行，待探究
             */
            InputStream is = context.getResources().openRawResource(id);

            return (null != is) ? BitmapUtil.readBitmap(is) : null;
        }

        public static Bitmap getImg(@NotNull String id) {
            return map.get(id);
        }
    }






    public static String getChapterTitle(String id) {
        Chapter chapter = getChapter(id);

        return null != chapter ? chapter.getTitle() : "";
    }

    public static String getMovesTitle(String id) {
        Moves move = getMove(id);

        return null != move ? move.getTitle() : "";
    }

    public static Bitmap getMovesGuidImg(String id) {
        Moves move = getMove(id);

        return null != move ? move.getFlagImg() : null;
    }

    public static Integer getMovesGuidImgId(String id) {
        Moves move = getMove(id);

        return null != move ? move.getGuideImgId() : null;
    }

}
